﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;

namespace Obra.Test
{
    abstract class HttpServer :
        IDisposable
    {
        private readonly Uri address;
        private readonly HttpListener httpListener = new HttpListener();

        /// <summary>
        /// c-tor
        /// </summary>
        /// <param name="address"></param>
        public HttpServer(
            Uri address)
        {
            if (!HttpListener.IsSupported)
            {
                throw new ArgumentException(Messages.HttpListenerNotSupported);
            }

            this.address = address;

            string localAddress = this.address.ToString().Replace(this.address.Host, "+");
            this.httpListener.Prefixes.Add(localAddress);
        }

        /// <summary>
        /// URI of the service to host.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The actual host name used will be automatically replaced with '+'.
        /// </para>
        /// </remarks>
        public Uri Address
        {
            get { return address; }
        }

        /// <summary>
        /// The underlying http server fronted by this class.
        /// </summary>
        protected HttpListener HttpListener
        {
            get { return httpListener; }
        }

        /// <summary>
        /// Start the server, and wait for the first request asynchronously.
        /// </summary>
        public virtual HttpServer Start()
        {
            this.HttpListener.Start();

            if (!this.HttpListener.IsListening)
            {
                throw new NullReferenceException(Messages.HttpListenerDidNotStart);
            }

            this.HttpListener.BeginGetContext(
                this.OnContextAvailable,
                this);

            return this;
        }

        /// <summary>
        /// Stop the server.
        /// </summary>
        public virtual void Stop()
        {
            if (this.HttpListener.IsListening)
            {
                this.HttpListener.Stop();
            }
        }

        /// <summary>
        /// Method called when a request is to be processed.
        /// </summary>
        protected abstract void OnContextAvailable(IAsyncResult asyncResult);

        #region IDisposable Members

        public virtual void Dispose()
        {
            this.Stop();
        }

        #endregion
    }
}
